import Taro from "@tarojs/taro";
import { OptionType } from "../../types/services/http";

/**
 * 被挂起的请求数组
 */
let refreshSubscribers: any[] = [];

/**
 * 刷新token 回调
 */
let refreshTokenFunc: ()=>Promise<any>;

/**
 * token失效标识
 */
let refreshTokenFlag: boolean = false;

/**
 * push所有请求到数组中
 * @param cb
 */
const subscribeTokenRefresh = (cb: any) => {
  refreshSubscribers.push(cb);
};

/**
 * 刷新请求（refreshSubscribers数组中的请求得到新的token之后会自执行,用新的token去请求数据)
 * @param token
 */
const onRrefreshed = (token: string) => {
  if (refreshSubscribers.length == 0) return;
  refreshSubscribers.map(cb => cb(token));
};

/**
 * 刷新token监听
 * @param callback
 */
const reigistRefreshTokenEvent = (callback: () => Promise<any>) => {
  refreshTokenFunc = callback;
};

/**
 * 执行刷新token相关操作
 */
const triggerRefresh = () => {
  refreshTokenFlag = true;
  refreshTokenFunc().then(res => {
    onRrefreshed(res.token || "");
    refreshSubscribers = [];
    refreshTokenFlag = false;
  }).catch(()=>{
    refreshSubscribers = [];
    refreshTokenFlag = false;
  })
};

/**
 * 执行刷新token以及调用后续接口逻辑
 * @param option
 */
const refreshToken = (option: OptionType) => {
  // 执行刷新逻辑
  if (!refreshTokenFlag) {
    triggerRefresh();
  }
  return new Promise(function(resolve, reject) {
    subscribeTokenRefresh((token: string) => {
      //替换token
      option.header.token = token;
      Taro.request(option)
        .then(res => {
          const code = res.data.code || res.statusCode;
          if (code === 200) {
            resolve(res);
          }
        })
        .catch(err => {
          reject(err);
        });
    });
  });
};

/**
 * 根据接口返回code执行相关操作
 * @param res
 * @param option
 */
const handleResponse = (res: any, option: OptionType) => {
  const code = res.data.code || res.statusCode;
  switch (Number(code)) {
    case 200: //成功
      return res;
    case 102: // 短token过期
      return refreshToken(option);
    default: {
      // 业务异常code码
      return res;
    }
  }
};

const baseRequest = (option: OptionType) => {
  return Taro.request(option)
    .then((res: any) => {
      return handleResponse(res, option);
    })
    .catch(e => {
      throw e;
    });
};

export { reigistRefreshTokenEvent, baseRequest };
